﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using ConsoleFx;

namespace Kindler
{
    [CommandLine(DisplayUsageOnError = true)]
    [ParameterUsage(ProgramMode.Normal, MinOccurences = 2, MaxOccurences = 2)]
    [ParameterUsage(ProgramMode.Help, MinOccurences = 0, MaxOccurences = 0)]
    public class Program : ConsoleProgram
    {
        public static int Main(string[] args)
        {
            return CommandLine.Run<Program>(args);
        }

        public Program()
        {
            var catalog = new AggregateCatalog();
            var container = new CompositionContainer(catalog);
            var batch = new CompositionBatch();

            batch.AddPart(this);

            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryCatalog(@"\")); // load from bin

            container.Compose(batch);
        }

        [ImportMany]
        public IEnumerable<IProcessor> Processors { get; set; }

        public override int ExecuteNormal(string[] parameters)
        {
#if DEBUG
            Console.WriteLine("Loaded Processors:");
            foreach (var processor in this.Processors)
            {
                Console.WriteLine("\t{0}", processor.GetType());
            }
#endif

            string htmlFilePath = parameters[0];
            string outputFilePath = parameters[1];
            char[] invalidPathChars = Path.GetInvalidPathChars();

            if (htmlFilePath.Any(c => invalidPathChars.Contains(c)))
            {
                throw new FormatException(string.Format("The file path '{0}' is not a valid path string.", htmlFilePath));
            }

            if (!File.Exists(htmlFilePath))
            {
                throw new FileNotFoundException(string.Format("The file at path '{0}' does not exist.", htmlFilePath));
            }

            if (outputFilePath.Any(c => invalidPathChars.Contains(c)))
            {
                throw new FormatException(string.Format("The file path '{0}' is not a valid path string.", outputFilePath));
            }

            XDocument htmlDocument;

            try
            {
                htmlDocument = XDocument.Load(htmlFilePath);
            }
            catch (Exception exc)
            {
                throw new FormatException(string.Format("The file '{0}' is not a valid XML file: {1}", htmlFilePath, exc.Message), exc);
            }

            foreach (IProcessor processor in this.Processors)
            {
                processor.Process(htmlDocument);
            }

            try
            {
                htmlDocument.Save(outputFilePath);
            }
            catch (Exception exc)
            {
                throw new IOException(string.Format("An error occured saving the Kindle book to file '{0}': {1}", outputFilePath, exc.Message), exc);
            }

            return 0;
        }

        public override void DisplayUsage()
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            ConsoleEx.WriteLine();
            ConsoleEx.WriteLine("Kindler");
            ConsoleEx.WriteLine();
            Console.ResetColor();

            ConsoleEx.WriteLine("HTML to Kindle converter program");
            ConsoleEx.WriteLine("http://kindler.codeplex.com/");
            ConsoleEx.WriteLine("Copyright (c) 2010 Dave Scriven");
            ConsoleEx.WriteLine();
            ConsoleEx.WriteLine("Converts HTML files into a Kindle readable document with a working table of contents and also allows custom plugins to be used.");
            ConsoleEx.WriteLine();
            ConsoleEx.WriteLine("kindler.exe <htmlFilePath> <outputFilePath>");
            ConsoleEx.WriteLine();
            ConsoleEx.WriteLine();
        }
    }
}